package com.eastedu.report.principal.assemble;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.eastedu.common.enums.DateCodeType;
import com.eastedu.report.common.model.parameter.ReportGenerateParameter;
import com.eastedu.report.common.model.po.CommonDimensionEntity;
import com.eastedu.report.common.model.po.TeacherTeachingActivityResourceUsagePeriodSubjectPO;
import com.eastedu.report.common.util.NumberFormatUtil;
import com.eastedu.report.common.util.SqlUtil;
import com.eastedu.report.mapper.TeacherTeachingActivityResourceUsageMapper;
import com.eastedu.report.principal.converter.PrincipalTeachingActivityConverter;
import com.eastedu.report.principal.model.teacher.exam.TeacherExamUsageReportData;
import com.eastedu.report.principal.util.ReportChartUtil;
import com.eastedu.report.principal.util.ReportDescriptionUtil;
import com.eastedu.template.chart.ChartMetadata;
import com.eastedu.template.util.ChartDataUtil;
import com.eastedu.utils.DateUtil;
import com.google.common.collect.Maps;
import lombok.Getter;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 教师资源应用分析 - 同步测验
 *
 * @author superman
 */
@Service
public class TeacherExamReportDataAssembly implements ReportDataAssembly {

    private final TeacherTeachingActivityResourceUsageMapper teacherTeachingActivityResourceUsageMapper;
    private final PrincipalTeachingActivityConverter principalTeachingActivityConverter;


    /**
     * Instantiates a new Teacher exam report data assembly.
     *
     * @param teacherTeachingActivityResourceUsageMapper the teaching activity teacher resource usage mapper
     * @param principalTeachingActivityConverter         the principal teaching activity converter
     */
    public TeacherExamReportDataAssembly(TeacherTeachingActivityResourceUsageMapper teacherTeachingActivityResourceUsageMapper, PrincipalTeachingActivityConverter principalTeachingActivityConverter) {
        this.teacherTeachingActivityResourceUsageMapper = teacherTeachingActivityResourceUsageMapper;
        this.principalTeachingActivityConverter = principalTeachingActivityConverter;
    }

    @Override
    public Map<String, Object> assemble(ReportGenerateParameter parameter, List<String> schoolPeriods, List<String> subjects) {
        DateCodeType codeType = parameter.getCodeType();
        Integer dateCode = parameter.getDateCode();
        Integer termDateCode = codeType.toTerm(dateCode);
        LambdaQueryWrapper<TeacherTeachingActivityResourceUsagePeriodSubjectPO> wrapper = SqlUtil.queryWrapper(parameter,
                                                                                                               w -> w.and(c ->
                                                                                                                                  c.or(a -> a.eq(CommonDimensionEntity::getCodeType, codeType).eq(CommonDimensionEntity::getDateCode, dateCode))
                                                                                                                                          .or(a -> a.eq(CommonDimensionEntity::getCodeType, DateCodeType.TERM).eq(CommonDimensionEntity::getDateCode, termDateCode)))
                                                                                                                       .eq(TeacherTeachingActivityResourceUsagePeriodSubjectPO::getTeachingActivity, "同步测验"),
                                                                                                               TeacherTeachingActivityResourceUsagePeriodSubjectPO.class);
        List<TeacherTeachingActivityResourceUsagePeriodSubjectPO> pos = teacherTeachingActivityResourceUsageMapper.selectList(wrapper);

        List<TeacherExamUsageReportData> usages = principalTeachingActivityConverter.convertToTeacherExamReportData(pos);

        Map<String, Object> map = Maps.newHashMap();
        List<TeacherExamUsageReportData> monthUsages = usages.stream().filter(teacherTeachingReportData -> DateCodeType.MONTH.equals(teacherTeachingReportData.getCodeType())).collect(Collectors.toList());
        // 2、当月，指标【同步测验环节-同步资源使用个数】≠ 0，则：
        // ---- 1）所有老师的指标【同步测验环节-同步资源使用个数】都 ≠ 0，则输出：本月同届资源使用情况：本月，xx（学届）xx（学科）的教师使用同届教学资源最多，为xx个。
        // ---- 2）存在有部分老师的指标【同步测验环节-同步资源使用个数】=0，则输出：本月同届资源使用情况：本月，xx（学届）xx（学科）的教师使用同届教学资源最多，为xx个；xx（学届）xx（学科）的教师暂未使用同届教学资源。
        long count = monthUsages.stream().map(TeacherExamUsageReportData::getFollowedResourceUseNumber)
                .filter(Objects::nonNull)
                .filter(num -> num > 0)
                .count();
        map.put("teacher_exam_followed_resource_usage_number_month_desc_show", count > 0);
        map.put("teacher_exam_followed_resource_usage_number_month_desc", Description.NUMBER.createResourceUsageDescription(monthUsages.stream().filter(data -> Objects.nonNull(data.getSchoolPeriod())).collect(Collectors.toList()),
                                                                                                                            data -> Objects.nonNull(data.getFollowedResourceUseNumber()) && data.getFollowedResourceUseNumber() > 0.0,
                                                                                                                            TeacherExamUsageReportData::getFollowedResourceUseNumber));
        // 2、当月，指标【同步测验环节-历史资源使用个数】≠ 0，则：
        // ---- 1）所有老师的指标【同步测验环节-历史资源使用个数】都 ≠ 0，则输出：本月历史资源使用情况：本月，xx（学届）xx（学科）的教师使用历史教学资源最多，为xx个。
        // ---- 2）存在有部分老师的指标【同步测验环节-历史资源使用个数】=0，则输出：本月历史资源使用情况：本月，xx（学届）xx（学科）的教师使用历史教学资源最多，为xx个；xx（学届）xx（学科）的教师暂未使用历史教学资源。
          count = monthUsages.stream().map(TeacherExamUsageReportData::getHistoryResourceUseNumber)
                  .filter(Objects::nonNull)
                  .filter(num -> num > 0)
                  .count();
        map.put("teacher_exam_history_resource_usage_number_month_desc_show", count > 0);
        map.put("teacher_exam_history_resource_usage_number_month_desc", Description.HISTORY.createResourceUsageDescription(monthUsages.stream().filter(data -> Objects.nonNull(data.getSchoolPeriod())).collect(Collectors.toList()),
                                                                                                                            data -> Objects.nonNull(data.getHistoryResourceUseNumber()) && data.getHistoryResourceUseNumber() > 0.0,
                                                                                                                            TeacherExamUsageReportData::getHistoryResourceUseNumber));

        List<ChartMetadata> subjectMetadata = ChartDataUtil.convertSubject(subjects);
        List<ChartMetadata> chartMetadata = ChartDataUtil.convertPeriod(schoolPeriods, Comparator.comparingInt(ChartMetadata::getOrder).reversed());
        // 图表： 📊本月各年级学科同步测验环节使用同步资源个数
        map.put("teacher_exam_followed_resource_usage_month_chart", ReportChartUtil.chart("本月各年级学科同步测验环节使用同步资源个数",
                                                                                          subjectMetadata,
                                                                                          chartMetadata,
                                                                                          monthUsages,
                                                                                          TeacherExamUsageReportData::getFollowedResourceUseNumber));

        // 图表：📊本月各年级学科同步测验环节使用历史资源个数
        map.put("teacher_exam_history_resource_usage_month_chart", ReportChartUtil.chart("本月各年级学科同步测验环节使用历史资源个数",
                                                                                         subjectMetadata,
                                                                                         chartMetadata,
                                                                                         monthUsages,
                                                                                         TeacherExamUsageReportData::getHistoryResourceUseNumber));


        List<TeacherExamUsageReportData> termUsages = usages.stream().filter(teacherTeachingReportData -> DateCodeType.TERM.equals(teacherTeachingReportData.getCodeType())).collect(Collectors.toList());

        // xx-xx学年（上/下）同步资源教师使用率
        String schoolYear = DateUtil.convertTermToSchoolYear(String.valueOf(termDateCode));
        String rateResourceUsageDescription = Description.RATE.createResourceUsageDescription(termUsages.stream().filter(data -> Objects.nonNull(data.getSchoolPeriod())).collect(Collectors.toList()),
                                                                                              data -> Objects.nonNull(data.getFollowedResourceUseRate()) && data.getFollowedResourceUseRate() > 0.0,
                                                                                              TeacherExamUsageReportData::getFollowedResourceUseRate);
        map.put("teacher_exam_resource_usage_rate_term_desc", rateResourceUsageDescription);
        // 2023-2024学年（上）各年级学科测验环节教师同步资源使用率
        chartMetadata.sort(Comparator.comparing(ChartMetadata::getOrder));
          count = termUsages.stream().map(TeacherExamUsageReportData::getFollowedResourceUseRate)
                  .filter(Objects::nonNull)
                  .filter(num -> num > 0)
                  .count();
        map.put("teacher_exam_resource_usage_term_chart_show", count > 0);
        map.put("teacher_exam_resource_usage_term_chart", ReportChartUtil.chart(schoolYear + "各年级学科测验环节教师同步资源使用率",
                                                                                subjectMetadata,
                                                                                chartMetadata,
                                                                                termUsages,
                                                                                TeacherExamUsageReportData::getFollowedResourceUseRate));
        return map;
    }


    /**
     * The enum Description.
     */
    @Getter
    enum Description {
        /**
         * Number description.
         */
        NUMBER("本月同步资源使用情况", () -> {
            Map<String, String> map = Maps.newHashMap();
            map.put("never", "本月，暂无教师使用同步测验资源");
            map.put("max", "本月，{0}的教师使用同步测验资源最多，为{1}个");
            map.put("min", "");
            map.put("zero", "；{0}的教师暂未使用同步测验资源");
            return map;
        }, Object::toString),
        /**
         * History description.
         */
        HISTORY("本月历史资源使用情况", () -> {
            Map<String, String> map = Maps.newHashMap();
            map.put("never", "本月，暂无教师使用历史教学资源");
            map.put("max", "本月，{0}的教师使用历史教学资源最多，为{1}个");
            map.put("min", "");
            map.put("zero", "");
            return map;
        }, Object::toString),
        /**
         * Rate description.
         */
        RATE("教师同步资源使用率", () -> {
            Map<String, String> map = Maps.newHashMap();
            map.put("never", "截止本月，本学期各学届的教师在教学环节均未使用过同步资源");
            map.put("max", "截止本月，本学期{0}教师在教学环节的同步资源使用率最高，为{1}");
            map.put("min", "；{0}教师在教学环节的同步资源使用率最低，为{1}");
            map.put("zero", "；{0}教师在教学环节暂未使用过同步资源");
            return map;
        }, NumberFormatUtil::formatPercent);

        private final String name;
        private final Supplier<Map<String, String>> supplier;
        private final Function<Number, String> format;

        Description(String name, Supplier<Map<String, String>> supplier, Function<Number, String> format) {
            this.name = name;
            this.supplier = supplier;
            this.format = format;
        }

        private String format(Number num) {
            if (Objects.isNull(this.format)) {
                return num.toString();
            }
            return this.format.apply(num);
        }

        /**
         * Create resource usage description string.
         *
         * @param usages    the usages
         * @param predicate the predicate
         * @param function  the function
         * @return the string
         */
        public String createResourceUsageDescription(List<TeacherExamUsageReportData> usages,
                                                     Predicate<TeacherExamUsageReportData> predicate,
                                                     Function<TeacherExamUsageReportData, Number> function) {
            BiFunction<Map<String, String>, Function<Number, String>, String> bifunction = ReportDescriptionUtil.minAndMaxDescription(usages, predicate, function);
            return bifunction.apply(this.getSupplier().get(), this::format);
        }

    }

}
